<?php
/*------------------------------------------------------------------------------
this file is part of Web Application Kit http://webappkit.net
Copyright (C) 2006 J.Ducastel <fredbird@fredbird.org>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
------------------------------------------------------------------------------*/

/**
* webappkit debug and errors core service
* @author J.Ducastel <fredbird@fredbird.org>
* @static
*/
class wakDebug extends wakService {
/*------------------------------------------------------------------------------
                                                                     constructor
------------------------------------------------------------------------------*/
	/**
	*
	* @access
	* @param
	* @return
	*/
	function wakDebug() {
		$this->__construct();
	}/**/
	
	/**
	*
	* @access
	* @param
	* @return
	*/
	function __construct() {
		parent::__construct();
	}/**/
/*------------------------------------------------------------------------------
                                                                  public methods
------------------------------------------------------------------------------*/
	/**
	* builds and returns a wakError instance with level 'error'
	* @access public
	* @param
	* @return wakError by reference
	* @static
	*/
	function & error($txt='') {
		// building error object
		return $this->buildError('error',$txt,2);
	}/**/
	
	/**
	* builds and returns a wakError instance with level 'warning'
	* @access public
	* @param
	* @return wakError by reference
	* @static
	*/
	function & warning($txt='') {
		// building error object
		return $this->buildError('warning',$txt,2);
	}/**/
	
	/**
	* builds and returns a wakError instance with level 'notice'
	* @access public
	* @param
	* @return wakError by reference
	* @static
	*/
	function & notice($txt='') {
		// building error object
		return $this->buildError('notice',$txt,2);
	}/**/
	
	/**
	* returns a string telling the caller of the current function/method
	* @access public
	* @param int $skipLevels (default 1)
	* @return string 
	* @static
	*/
	function getCaller($skipLevels=0) {
		// skipping one more level : this call
		$skipLevels+=1;
		// getting caller
		$backtrace=debug_backtrace();
		// echo '<pre>'; var_dump($backtrace); echo '</pre>';
		if (!isset($backtrace[$skipLevels])) return '!!too much skipLevels!!';
		// defining caller string
		$caller='';
		$caller.=isset($backtrace[$skipLevels]['class'])?
			$backtrace[$skipLevels]['class'].$backtrace[$skipLevels]['type']
			:basename($backtrace[$skipLevels]['file']).': line '.$backtrace[$skipLevels]['line'].': ';
		$caller.=isset($backtrace[$skipLevels]['function'])?
			$backtrace[$skipLevels]['function'].'():':'';
		//$caller.='('.$backtrace[$skipLevels]['file'].')';
		return $caller;
	}/**/
	
	/**
	* checks if the var hasn't the good type/class, returns a wakError instance if so
	* @param mixed $param by reference
	* @param string $types
	* @param string $name
	* @param string $errorLevel
	* @return false|wakError
	*/
	function hasWrongType(& $param,$types,$name=NULL,$errorLevel='notice') {
		// checking type
		$wrongType=!$this->checkTypes($param,$types);
		// type is ok
		if (!$wrongType) return $wrongType;
		// wrong type indeed, have to return an error
		$realtype=gettype($param);
		if (is_object($param)) $realtype.=' '.get_class($param);
		$txt="parameter $name has wrong type : $realtype instead of $types";
		return $this->buildError($errorLevel,$txt,3);
	}/**/

	/**
	* returns a dump of the var
	* @static
	* @return string
	* @param mixed $var by reference the var to dump
	* @param string $mode text html
	* @param int $cut
	*/
	function varDump(&$var, $mode='html',$cut=50, $niv=1) {
		//echo $niv;
		// defining markup
		switch ($mode) {
			case 'html':
				$beforeType='';
				$afterType='';
				$beforeDetails='(';
				$afterDetails=')';
				$beforeValue=' <var>';
				$afterValue='</var>';
				$newline='<br />';
				$indent=''; for ($f=1; $f<=$niv; $f++) $indent.='. ';
				break;
			case 'text':
			default:
				$beforeType='';
				$afterType='';
				$beforeDetails='(';
				$afterDetails=')';
				$beforeValue=' [';
				$afterValue=']';
				$newline=chr(13).chr(10);
				$indent=''; for ($f=1; $f<$niv; $f++) $indent.=chr(11);
		}
		// analysing var, building and returning string
		$details='';
		$type=gettype($var);
		$value='';
		switch (true) {
			/*case is_numeric($var):
				$value=strval($var);
				break;*/
			case is_string($var):
				//$type='string';
				$details=strlen($var);
				$value=substr($var,0,$cut);
				$value=wakdebug::xmlentities($value);
				break;
			case is_array($var):
				//$type='array';
				$details=count($var);
				foreach ($var as $key => $item)
					$value.=$newline.$indent.$key.' = '.wakdebug::vardump($item,$mode,$cut,$niv+1);
				break;
			case is_object($var):
				$details=get_class($var);
				if ($parent=get_parent_class($var)) $details.=' extends '.$parent;
				$subvars=get_object_vars($var);
				foreach ($subvars as $key => $item) {
					// skipping vars starting by _
					if ($key[0]=='_') continue;
					$value.=$newline.$indent.$key.' = '.wakdebug::vardump($item,$mode,$cut,$niv+1);
				}
				break;
			case is_bool($var):
				//$details=
				$details=$var?'true':'false';
				$value='';
				break;
			/*case is_null($var):
				
				break;*/
			default:
				//$type=gettype($var);
				$value=substr(strval($var),0,$cut);
		}
		// building and returning string
		$r=$beforeType.$type.$afterType
		.$beforeDetails.$details.$afterDetails
		.$beforeValue.$value.$afterValue;
		if ($niv==1) $r.=$newline;
		return $r;
	}/**/
	
	/**
	*
	*/
	function getErrors() {
		return $this->errors;
	}
/*------------------------------------------------------------------------------
                                                                      properties
------------------------------------------------------------------------------*/
	var $errors=array();
/*------------------------------------------------------------------------------
                                                                 private methods
------------------------------------------------------------------------------*/
	/**
	* builds a wakerror instance, references it into the errors namespace, and returns it
	* @access private
	* @return wakError by reference
	* @param string level error warning notice
	* @param string txt error description
	* @param int $skipCallLevels (default 2)
	*/
	function & buildError($level,$txt,$skipCallLevels=2) {
		// building instance
		$caller=$this->getcaller($skipCallLevels);
		$error=& new wakError($caller,$level,$txt);
		// referencing
		// $errors=& wakNameSpace::getspace('wakerrors');
		// $errors->pushRef($error);
		$this->errors[]=& $error;
		// logging error
		// wakLog::entry($error->getAsText());
		// returning instance
		return $error;
	}
	
	/**
	* checks the type/class of a var
	* @param mixed $param (by reference) the var to check
	* @param string $type the type or class requested
	* @return bool
	* @static
	*/
	function checkType(&$param,$type) {
		switch (strtolower($type)) {
			case 'string':
				if (!is_string($param)) return false;
				break;
			case 'int':
			case 'integer':
				if (!is_int($param)) return false;
				break;
			case 'float':
				if (!is_float($param)) return false;
				break;
			case 'numeric':
				if (!is_numeric($param)) return false;
				break;
			case 'resource':
				if (!is_resource($param)) return false;
				break;
			case 'scalar':
				if (!is_scalar($param)) return false;
				break;
			case 'array':
				if (!is_array($param)) return false;
				break;
			case 'bool':
			case 'boolean':
				if (!is_bool($param)) return false;
				break;
			case 'null':
			case 'NULL':
				if (!is_null($param)) return false;
				break;
			default: // type is treated as a class name
				if (!is_object($param) 
				or strtolower(get_class($param))!=strtolower($type))
					return false;
		}
		return true;
	}
	
	/**
	* checks the type/class of a var upon a list of types/class separated by spaces
	* @param mixed $param
	* @param string array $types
	* @return bool
	* @static
	*/
	function checkTypes(&$param,$types) {
		if (is_string($types)) $types=explode(' ',$types);
		foreach ($types as $type) {
			if ($this->checkType($param,$type)) return true;
		}
		return false;
	}
	
	/**
	* replace xml special chars by their entity
	* @param string $text
	* @static
	* @return string
	*/
	function & xmlentities($str) {
		$str=str_replace('&','&amp;',$str);
		$str=str_replace('"','&quot;',$str);
		$str=str_replace("'",'&apos;',$str);
		$str=str_replace('<','&lt;',$str);
		$str=str_replace('>','&gt;',$str);
		return $str;
	}
/*------------------------------------------------------------------------------

------------------------------------------------------------------------------*/
}

/**
*
*/
class wakError {
/*------------------------------------------------------------------------------
                                                                     constructor
------------------------------------------------------------------------------*/
	function wakError($caller,$level='notice', $txt='') {
		// $this->caller=$this->getcaller(2);
		$this->caller=$caller;
		$this->txt=$txt;
		$this->time=wak::timeCounter();
		$this->level=$level;
		//echo "error called by $caller";
		// echo '<p>'.$this->getAsText().'</p>';
	}
	
	function getAsText() {
		return $this->level.' '.$this->time.' '.$this->caller.' '.$this->txt;
	}
/*------------------------------------------------------------------------------
                                                                  public methods
------------------------------------------------------------------------------*/

/*------------------------------------------------------------------------------
                                                                      properties
------------------------------------------------------------------------------*/
	var $caller;
/*------------------------------------------------------------------------------
                                                                 private methods
------------------------------------------------------------------------------*/
}

/**
*
*/
/*class wakException extends Exception {
	
	public function __construct($message=NULL, code=0) {
		$this->message=$message;
		$this->code=$code;
	}
}*/

?>
